/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package parser;

import java.lang.reflect.Field;
import java.util.Vector;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
 *
 * @author Evan
 */
public class Node {
    public static final int ROOT = 100;
    public static final int ASSIGNMENT = 200;
    public static final int NUM_EXPRESSION = 300;
    public static final int OPP1 = 400;
    public static final int OPP2 = 500;
    public static final int NUMBER = 600;
    public static final int IF_THEN = 700;
    public static final int NUM_CONDITION = 800;
    public static final int VARIABLE = 900;
    public static final int EXPRESSION = 1000;
    public static final int BOOL_EXPRESSION = 1100;
    public static final int STR_EXPRESSION = 1200;
    public static final int BOOL_CONDITION = 1300;

    private Vector<Node> children = new Vector<Node>();
    public String image;
    public int kind;
    public Node parent;
    public Node(int name) {
       this.kind = name;
    }
    public Node(Token t) {
        image = t.image;
        kind = t.kind;
    }
    public void add(Node n) {
        n.parent = this;
        children.add(n);
    }
    public boolean add(Node n, int parent) {
        if(parent == kind) {
            n.parent = this;
            add(n);
            return true;
        } else {
            for(Node c : children) {
                if(c.add(n, parent)) {
                    break;
                }
            }
        }
        return false;
    }
    public Node[] getChildren() {
        return children.toArray(new Node[children.size()]);
    }
    public Node getChild(int index) {
        return children.elementAt(index);
    }
    public int getChildCount() {
        return children.size();
    }
    public void remove(Node n) {
        children.remove(n);
    }
    public void remove(int index) {
        children.remove(index);
    }
    public Object parse() {
        return parse(null);
    }
    public Object parse(ParserInterface p) {
        if(kind == ROOT) {
            for(Node c : children) {
                    c.parse(p);
            }
        } else if(kind == ASSIGNMENT) {
            Node assign = getChild(1); //=, :=, <=
            String var = null;
            Object exp = null;
            if(assign.kind == PIELexerConstants.ASSIGN) {
                var = (String)getChild(0).getChild(0).image; //VARIABLE
                exp = getChild(2).parse(p); //EXPRESSION
            } else if(assign.kind == PIELexerConstants.R_ASSIGN) {
                exp = getChild(0).parse(); //EXPRESSION
                var = (String)getChild(2).getChild(0).image; //VARIABLE
            }
            p.putVariable(var, exp);
        } else if(kind == IF_THEN) {
            //BOOL_EXPRESSION
            if((Boolean)getChild(1).parse()) {
                getChild(3).parse(p); //ASSIGNMENT
            }
        } else if(kind == NUM_CONDITION) {
            Node compare = getChild(1); //=, !=, <=, >=, <, >
            Object exp1 = getChild(0).parse(); //EXPRESSION
            Object exp2 = getChild(2).parse(); //EXPRESSION
            if(compare.kind == PIELexerConstants.EQUAL) {
                return exp1 == exp1;
            } else if(compare.kind == PIELexerConstants.NOT_EQUAL) {
                return exp1 != exp1;
            } else if(compare.kind == PIELexerConstants.GREATER_THAN_EQUAL) {
                return (Double)exp1 >= (Double)exp1;
            } else if(compare.kind == PIELexerConstants.LESS_THAN_EQUAL) {
                return (Double)exp1 <= (Double)exp2;
            } else if(compare.kind == PIELexerConstants.GREATER_THAN) {
                return (Double)exp1 > (Double)exp2;
            } else if(compare.kind == PIELexerConstants.LESS_THAN) {
                return (Double)exp1 < (Double)exp2;
            }
        } else if(kind == BOOL_CONDITION) {
            if(getChildCount() == 1) {
                //There are no bool operators
                return getChild(0).parse();
            }
            boolean v = (Boolean)getChild(0).parse(); //BOOL_EXPRESSION
            for(int i = 2; i < getChildCount(); i += 2) {
                Node boolNode = getChild(i - 1); //AND, OR
                if(boolNode.kind == PIELexerConstants.AND) {
                    v = v && (Boolean)getChild(i).parse(); //BOOL_EXPRESSION
                } else if(boolNode.kind == PIELexerConstants.OR) {
                    v = v || (Boolean)getChild(i).parse(); //BOOL_EXPRESSION
                }
            }
            return v;
        } else if(kind == BOOL_EXPRESSION) {
            if(getChildCount() == 1) {
                //Simple
                return getChild(0).parse(p); //TRUE, FALSE
            }
            if(getChildCount() == 2) {
                //Not operator
                return !(Boolean)getChild(1).parse(); //TRUE, FALSE
            }

        } else if(kind == VARIABLE) {
            //Return the value of the variable
            return p.getVariable((String)getChild(0).parse());
        } else if(kind == EXPRESSION) {
            return getChild(0).parse(p); //NUM_EXPRESSION, BOOL_EXPRESSION, STR_EXRESSION
        } else if(kind == NUM_EXPRESSION) {
            if(getChildCount() == 1) {
                //There are no opperators
                return getChild(0).parse(p); //OPP1
            }
            Double v = (Double)getChild(0).parse();
            for(int i = 2; i < getChildCount(); i += 2) {
                Node oppNode = getChild(i - 1); //+, -
                if(oppNode.kind == PIELexerConstants.PLUS) {
                    v += (Double)getChild(i).parse(); //OPP1
                } else if(oppNode.kind == PIELexerConstants.MINUS) {
                    v -= (Double)getChild(i).parse(); //OPP1
                }
            }
            return v;
        } else if(kind == OPP1) {
            if(getChildCount() == 1) {
                //There are no powers
                return getChild(0).parse(p); //OPP2
            }
            Node leftNode = getChild(1);
            if(leftNode.kind == PIELexerConstants.POWER) {
                Double v1 = (Double)getChild(0).parse();
                Double v2 = (Double)getChild(2).parse();
                return Math.pow(v1, v2);
            }
        } else if(kind == OPP2) {
            if(getChildCount() == 1) {
                //There are no operators
                return getChild(0).parse(p); //NUMBER
            }
            Double v =(Double)getChild(0).parse();
            for(int i = 2; i < getChildCount(); i += 2) {
                Node oppNode = getChild(i - 1); //*, /, MOD
                if(oppNode.kind == PIELexerConstants.TIMES) {
                    v *= (Double)getChild(i).parse(); //NUMBER
                } else if(oppNode.kind == PIELexerConstants.DIVIDE) {
                    v /= (Double)getChild(i).parse(); //NUMBER
                } else if(oppNode.kind == PIELexerConstants.MOD) {
                    v %= (Double)getChild(i).parse(); //NUMBER
                }
            }
            return v;
            
        } else if(kind == NUMBER) {
            Node leftToken = getChild(0);
            if(leftToken.kind == PIELexerConstants.L_PAREN) {
                //Returns expression
                return (Double)getChild(1).parse();
            } else if(leftToken.kind == PIELexerConstants.MINUS) {
                //Returns negated expression
                return -(Double)getChild(1).parse();
            } else if(leftToken.kind == VARIABLE) {
                //Returns the value of the variable
                return leftToken.getChild(0).parse();
            }
            return Double.parseDouble((String)getChild(0).parse());
        } else if(kind == PIELexerConstants.TRUE) {
            return true;
        } else if(kind == PIELexerConstants.FALSE) {
            return false;
        } else {
            return image;
        }
        return null;
    }
    @Override
    public String toString() {
        return getString(0);
    }
    private String getString(int level) {
        String result = "";
        //Check if it is a token
        if(image != null) {
            result = image;
        } else { //Get field name
            Field[] fields = getClass().getFields();
            for(Field f : fields) {
                Object value = null;
                try {
                    value = f.get(this);
                } catch (IllegalArgumentException ex) {
                    Logger.getLogger(Node.class.getName()).log(Level.SEVERE, null, ex);
                } catch (IllegalAccessException ex) {
                    Logger.getLogger(Node.class.getName()).log(Level.SEVERE, null, ex);
                }
                    if(value instanceof Integer) {
                        if ((Integer)value == kind) {
                        result = f.getName();
                        break;
                    }
                }
            }
        }
        for(Node c : children) {
            result += "\n";
            for(int i = 0; i < level + 1; i++) {
                result += "\t";
            }
            result += c.getString(level + 1);
        }
        return result;
    }
}
